﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Collections;

public static class StringExtensions
{
    /// <summary>
    /// Creates a stream of the string whose backing store is memory
    /// </summary>
    /// <param name="source">The string is stored in stereo</param>
    /// <returns>A stream that consists of the values of the source</returns>
    public static Stream ToStream(this string source)
    {
        if (source == null) throw new ArgumentNullException(@string.of(() => source));

        using (var memoryStream = new MemoryStream())
        {
            var buffer = new UnicodeEncoding().GetBytes(source.RemoveIllegalXmlCharaters());

            memoryStream.Write(buffer, 0, buffer.Length);
            return memoryStream;
        }
    }

    /// <summary>
    /// Remove data from string that contains characters that are illegal according to the XML specifications
    /// </summary>
    /// <param name="source">String to be clean</param>
    /// <see cref="http://seattlesoftware.wordpress.com/2008/09/11/hexadecimal-value-0-is-an-invalid-character/"/>
    /// <returns> A new string that is equivalent to this string except for the removed illegal characters.</returns>
    public static string RemoveIllegalXmlCharaters(this string source)
    {
        StringBuilder buffer = new StringBuilder(source.Length);
        foreach (var character in source.Where(x => IsLegalXmlChar(x)))
        {
            buffer.Append(character);
        }
        return buffer.ToString();
    }

    /// <summary>
    /// Whether a given character is allowed by XML 1.0.
    /// </summary>
    private static bool IsLegalXmlChar(int character)
    {
        return
        (
             character == 0x9 /* == '\t' == 9   */          ||
             character == 0xA /* == '\n' == 10  */          ||
             character == 0xD /* == '\r' == 13  */          ||
            (character >= 0x20 && character <= 0xD7FF) ||
            (character >= 0xE000 && character <= 0xFFFD) ||
            (character >= 0x10000 && character <= 0x10FFFF)
        );
    }
}